package com.airtight.screens;

import android.content.Context;
import android.view.MotionEvent;

import com.airtight.game.GameState;
import com.airtight.interfaces.Screen;
import com.airtight.objects.Background;
import com.airtight.objects.Ball;
import com.airtight.objects.Column;
import com.airtight.objects.Shard;
import com.airtight.programs.ColorShaderProgram;
import com.airtight.programs.TextureShaderProgram;
import com.airtight.util.AccelerometerHandler;
import com.example.android.opengl.R;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

import static android.opengl.Matrix.translateM;

public class World extends Screen{
    private AccelerometerHandler accelHandler;
    private int score;
    private float ratio;
    private boolean pause;

    private Random random;
    private Context context;
    private ScreenManager screenManager;
    private GameState gameState;

    public Background background;
    private Ball ball;
    private Shard shard;

    private Column[] left_columns;
    private Column[] right_columns;
    private Column[] bottom_columns;
    private Column[] top_columns;

    private ArrayList<Integer> visibleCols = new ArrayList(Arrays.asList(1,2,3,4,5,6,7));

    private TextureShaderProgram textureProgram;
    private ColorShaderProgram colorProgram;


    World(Context context, ScreenManager screenManager, GameState gameState){
        loadObjects(context,screenManager,gameState);
        loadServices();
    }

    private void loadObjects(Context context, ScreenManager screenManager, GameState gameState){
        this.context = context;
        this.screenManager = screenManager;
        this.gameState = gameState;
        this.ratio = this.gameState.getRatio();

        this.background = this.gameState.objects.background;
        this.ball = this.gameState.objects.ball;
        this.shard = this.gameState.objects.shard;

        this.left_columns = this.gameState.objects.left_columns;
        this.right_columns = this.gameState.objects.right_columns;
        this.top_columns = this.gameState.objects.top_columns;
        this.bottom_columns = this.gameState.objects.bottom_columns;
    }

    private void loadServices(){
        accelHandler = new AccelerometerHandler(context);
        textureProgram = new TextureShaderProgram(context, R.raw.texture_vertex_shader, R.raw.texture_fragment_shader);
        colorProgram = new ColorShaderProgram(context);
        random = new Random();
    }

    public void changeSurface(float ratio){
        this.ratio = ratio;
        float altratio = 1/ratio;
        screenManager.setRatio(ratio);
        //Log.d("change surface ","world");
    }

    public void update() {
        if (!pause) {
            ball.Fall();
            ball.MoveSide(accelHandler.getAccelX());
            shard.Fade();
            moveColumns();
            collided();
            if (collectedShard() || shard.transparency <= 0) {                    //resets shard if it was collected or it fades out
                gameState.objects.spawnShard(ratio);
                this.shard = gameState.objects.shard;
            }

        }
    }

    public void draw() {
        background.drawBackground(textureProgram, screenManager.getAssets().background_texture);
        drawColumns();
        ball.drawBall(textureProgram,screenManager.getAssets().ball_texture);
        shard.drawShard(textureProgram, screenManager.getAssets().shard_texture);
    }

    public void pause() {
        pause = true;
    }

    public void resume() {
        pause = false;
    }

    public void dispose() {

    }

    public void onBackPressed() {
        EndGame();
    }

    public void TouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                pause = !pause;
                break;

        }
    }

    public boolean getState() {
        return pause;
    }

    public String toString() {
        return "World";
    }

    private void collided(){
        float vl = left_columns.length + 2;
        float hz = top_columns.length;
        int column_hit = (int) ((ball.getY()+1)*(hz-1)) - 1;

        if(ball.getX() <= -1 + 3/hz && column_hit>=0){
            if(left_columns[column_hit].getX()+2/hz>=ball.getX()){
                ball.setX(left_columns[column_hit].getX()+2/hz);
            }
            checkHorDeath();
        }

        if(ball.getX() >= 1 - 3/hz && column_hit>=0){
            if(right_columns[column_hit].getX()-2/hz<=ball.getX()){
                ball.setX(right_columns[column_hit].getX()-2/hz);
            }
            checkHorDeath();
        }

        column_hit = (int) ((ball.getX()+1)*(hz/2));
        if(bottom_columns[column_hit].collidable) {
            if (ball.ballMatrix[13] - 1/hz <= bottom_columns[column_hit].getY()) {
                ball.velocity += ball.acceleration;
                ball.down = false;
                resetBottom();
            }
        }
        else{
            checkVertDeath();
        }
    }

    private void drawColumns(){
        for (Column left_column : left_columns) {
            left_column.drawColumn(textureProgram, screenManager.getAssets().column_texture);
        }

        for (Column right_column : right_columns) {
            right_column.drawColumn(textureProgram, screenManager.getAssets().column_texture);
        }

        for (Column top_column : top_columns) {
            top_column.drawColumn(textureProgram, screenManager.getAssets().column_texture);
        }

        for (Column bottom_column : bottom_columns) {
            if (bottom_column.collidable) {
                bottom_column.drawColumn(textureProgram, screenManager.getAssets().column_texture);
            }
        }
    }

    private void moveColumns(){
        float vl = left_columns.length + 2;
        float hz = top_columns.length;
        for (Column left_column : left_columns) {
            if (left_column.getX() >= -1 + 1/hz) {
                left_column.setTighter(false);
            }
            if (left_column.getX() <= -1 -1/hz) {
                left_column.setTighter(true);
            }
            if (left_column.getTighter()) {
                translateM(left_column.getMatrix(), 0, 0.003f, 0, 0);
            } else {
                translateM(left_column.getMatrix(), 0, -0.003f, 0, 0);
            }
        }

        for (Column right_column : right_columns) {
            if (right_column.getX() <= 1 - 1/hz) {                //pixels_across - colswidth
                right_column.setTighter(false);
            }
            if (right_column.getX() >= 1 + 1/hz) {
                right_column.setTighter(true);
            }
            if (right_column.getTighter()) {
                translateM(right_column.getMatrix(), 0, -0.003f, 0, 0);
            } else {
                translateM(right_column.getMatrix(), 0, 0.003f, 0, 0);
            }

        }

        if(bottom_columns[0].getY() < -1 + 1/(vl)){
            moveBottom();
        }
    }

    private void moveBottom(){
        for (Column bottom_column : bottom_columns) {
            if (bottom_column.collidable) {
                translateM(bottom_column.getMatrix(), 0, 0, 0.002f, 0);
            }
        }
    }

    private void resetBottom(){
        float vl = left_columns.length + 2;
        float hz = top_columns.length;
        int lvl;

        if(ball.bounces>=64){												//maxes out number of hidden columns
            lvl=6;
        }
        else if(ball.bounces>0){											//level increase is based on base 2 logarithm
            lvl = (int) Math.floor((Math.log(ball.bounces)/Math.log(2)));
        }
        else{															//if # of bounces is too low, make lvl =0 by default
            lvl=0;
        }

        for (Column bottom_column : bottom_columns) {
            bottom_column.setY(-1 -1/hz);
            bottom_column.collidable = true;
        }
        for(int i = 0; i < lvl; i++){									    //for the amount of levels
            int rand = random.nextInt(visibleCols.toArray().length);				//picks random column (not first or last) to make hidden
            int p = (int) visibleCols.toArray()[rand];
            bottom_columns[p].collidable = false;
            visibleCols.remove(rand);
        }
        visibleCols = new ArrayList(Arrays.asList(1,2,3,4,5,6,7));
        ball.bounces++;
    }

    private boolean collectedShard(){
        float vl = left_columns.length + 2;
        float hz = top_columns.length;
        float ball_x = ball.getX() + 10;
        float ball_y = ball.getY() + 10;

        float shard_x = shard.getX() + 10;
        float shard_y = shard.getY() + 10;

        float x_sb_distance = Math.abs(ball_x - shard_x);
        float y_sb_distance = Math.abs(ball_y - shard_y);

        if(x_sb_distance <= 2/hz){
            if(y_sb_distance <= 1/hz){
                //score++;
                //ResizeScore();
                return true;
            }
        }
        return false;
    }

    private void checkHorDeath(){
        float hz = top_columns.length;
        if(Math.abs(ball.getX()) >= 1 - 2/hz){
            EndGame();
        }
    }

    private void checkVertDeath(){
        if (ball.getY() < -1) {
            EndGame();
        }
    }

    private void EndGame(){
        float vl = left_columns.length + 2;
        ball.resetParams();
        pause = false;
        for (Column bottom_column : bottom_columns) {
            bottom_column.setY(-1 + 1/vl);
            bottom_column.collidable = true;
        }
        screenManager.setMainMenu();
    }

    private void ResizeScore() {
        //TODO implement score
    }
}
